
package com.ymx.sdk.widget.recyclerview;

import com.ymx.sdk.R;
import com.ymx.sdk.util.DensityUtils;
import com.ymx.sdk.util.ViewUtils;
import com.ymx.sdk.widget.PullToRefreshView.PullToRefreshBase;
import com.ymx.sdk.widget.PullToRefreshView.internal.EmptyViewMethodAccessor;
import com.ymx.sdk.widget.PullToRefreshView.internal.IndicatorLayout;
import com.ymx.sdk.widget.recyclerview.adapterItemAnimator.BaseAnimationAdapter;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;

public abstract class AutoPullToRefreshRecyclerViewBase<T extends RecyclerView> extends
        PullToRefreshBase<T> {
    private LayoutInflater mInflater;
    private Boolean isEnable = true;
    private Context mContext;

    public Boolean getIsEnable() {
        return isEnable;
    }

    public void setIsEnable(Boolean isEnable) {
        this.isEnable = isEnable;

    }

    // footer view
    private RelativeLayout mFooterView;
    // private TextView mLabLoadMore;
    private ProgressBar mProgressBarLoadMore;

    // Listener to process load more items when user reaches the end of the list
    private OnLoadMoreListener mOnLoadMoreListener;
    // To know if the list is loading more items
    private boolean mIsLoadingMore = false;
    private int mCurrentScrollState;

    private static FrameLayout.LayoutParams convertEmptyViewLayoutParams(ViewGroup.LayoutParams lp) {
        FrameLayout.LayoutParams newLp = null;

        if (null != lp) {
            newLp = new FrameLayout.LayoutParams(lp);

            if (lp instanceof LayoutParams) {
                newLp.gravity = ((LayoutParams) lp).gravity;
            } else {
                newLp.gravity = Gravity.CENTER;
            }
        }

        return newLp;
    }

    private boolean mLastItemVisible;
    private OnLastItemVisibleListener mOnLastItemVisibleListener;
    private View mEmptyView;

    private IndicatorLayout mIndicatorIvTop;
    private IndicatorLayout mIndicatorIvBottom;

    private boolean mShowIndicator;
    private boolean mScrollEmptyView = true;
    private RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int state) {
            /**
             * Check that the scrolling has stopped, and that the last item is
             * visible.
             */
            if (state == recyclerView.SCROLL_STATE_IDLE && null != mOnLastItemVisibleListener
                    && mLastItemVisible) {
                mOnLastItemVisibleListener.onLastItemVisible();
            }

            if (isEnable) {// 是否开启滑动

                // if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
                // view.invalidateViews();
                // }

                mCurrentScrollState = state;
            }
            super.onScrollStateChanged(recyclerView, state);

        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            int totalItemCount = mRefreshableView.getLayoutManager().getItemCount();
            int firstVisibleItem = ((LinearLayoutManager) mRefreshableView.getLayoutManager())
                    .findFirstVisibleItemPosition();
            int visibleItemCount = mRefreshableView.getLayoutManager().getChildCount();
            if (null != mOnLastItemVisibleListener) {
                mLastItemVisible = (totalItemCount > 0)
                        && (firstVisibleItem + visibleItemCount >= totalItemCount - 1);
            }

            // If we're showing the indicator, check positions...
            if (getShowIndicatorInternal()) {
                updateIndicatorViewsVisibility();
            }

            // Finally call OnScrollListener if we have one

            if (null != mOnScrollListener) {
                super.onScrolled(recyclerView,
                        dx, dy);
            }

            if (isEnable) {// 是否开启滑动
                if (mOnScrollListener != null) {
                    super.onScrolled(recyclerView,
                            dx, dy);
                }

                if (mOnLoadMoreListener != null) {

                    if (visibleItemCount == totalItemCount) {// 刚好铺满一个屏幕，
                        hideLoadMoreFooter();
                        return;
                    }

                    boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount;// 滑动到底部

                    if (!mIsLoadingMore && loadMore
                            && mCurrentScrollState != RecyclerView.SCROLL_STATE_IDLE) { // 判断如果滚动到底部，并且已经停止滚动的时候，我们就显示底部加载更多。
                        showLoadMoreFooter();
                        mIsLoadingMore = true;
                        onLoadMore();// 回调监听
                    }

                }
            }

        }
    };

    public AutoPullToRefreshRecyclerViewBase(Context context) {
        super(context);
        mRefreshableView.addOnScrollListener(mOnScrollListener);
        initData(context);
    }

    public AutoPullToRefreshRecyclerViewBase(Context context, AttributeSet attrs) {
        super(context, attrs);
        mRefreshableView.addOnScrollListener(mOnScrollListener);
        initData(context);

    }

    public AutoPullToRefreshRecyclerViewBase(Context context, Mode mode) {
        super(context, mode);
        mRefreshableView.addOnScrollListener(mOnScrollListener);
        initData(context);

    }

    public AutoPullToRefreshRecyclerViewBase(Context context, Mode mode, AnimationStyle animStyle) {
        super(context, mode, animStyle);
        mRefreshableView.addOnScrollListener(mOnScrollListener);
        initData(context);

    }

    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
        mOnLoadMoreListener = onLoadMoreListener;
    }

    private void initData(Context context) {
        mContext = context;
        mInflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        // footer
        mFooterView = (RelativeLayout) mInflater.inflate(
                R.layout.listview_load_more_footer, this, false);// 加载底部view

        mProgressBarLoadMore = (ProgressBar) mFooterView
                .findViewById(R.id.pb_loading);
        if (mRefreshableView instanceof RecyclerView) {
            /*
             * mFooterView.setLayoutParams(new RecyclerView.LayoutParams(
             * RecyclerView.LayoutParams.MATCH_PARENT,
             * RecyclerView.LayoutParams.WRAP_CONTENT));
             */
        }
    }

    boolean isAddFront;

    public void addFrontFooterView(boolean isAddFront) {
        this.isAddFront = isAddFront;
    }

    /**
     * Gets whether an indicator graphic should be displayed when the View is in
     * a state where a Pull-to-Refresh can happen. An example of this state is
     * when the Adapter View is scrolled to the top and the mode is set to
     * {@link Mode#PULL_FROM_START}. The default value is <var>true</var> if
     * {@link PullToRefreshBase#isPullToRefreshOverScrollEnabled()
     * isPullToRefreshOverScrollEnabled()} returns false.
     * 
     * @return true if the indicators will be shown
     */
    public boolean getShowIndicator() {
        return mShowIndicator;
    }

    /**
     * Pass-through method for {@link PullToRefreshBase#getRefreshableView()
     * getRefreshableView()}. {@link AdapterView#setAdapter(Adapter)}
     * setAdapter(adapter)}. This is just for convenience!
     * 
     * @param adapter - Adapter to set
     */
    public void setAdapter(HFListRecyclerAdapter adapter) {
        adapter.addFooterView(mFooterView);
        mRefreshableView.setAdapter(adapter);
    }
    /**
     * recyclerview with Animation
     *
     * @param adapter
     */
    public void setAdapter(BaseAnimationAdapter adapter) {
        if (adapter.getWrappedAdapter() instanceof HFListRecyclerAdapter) {
            ((HFListRecyclerAdapter) adapter.getWrappedAdapter()).addFooterView(mFooterView);
        } else {
            throw new IllegalArgumentException("You Need HFListRecyclerAdapter!");
        }
        mRefreshableView.setAdapter(adapter);
    }

    /**
     * Sets the Empty View to be used by the Adapter View.
     * <p/>
     * We need it handle it ourselves so that we can Pull-to-Refresh when the
     * Empty View is shown.
     * <p/>
     * Please note, you do <strong>not</strong> usually need to call this method
     * yourself. Calling setEmptyView on the AdapterView will automatically call
     * this method and set everything up. This includes when the Android
     * Framework automatically sets the Empty View based on it's ID.
     * 
     * @param newEmptyView - Empty View to be used
     */
    public final void setEmptyView(View newEmptyView) {
        FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();

        if (null != newEmptyView) {
            // New view needs to be clickable so that Android recognizes it as a
            // target for Touch Events
            newEmptyView.setClickable(true);

            ViewParent newEmptyViewParent = newEmptyView.getParent();
            if (null != newEmptyViewParent && newEmptyViewParent instanceof ViewGroup) {
                ((ViewGroup) newEmptyViewParent).removeView(newEmptyView);
            }

            // We need to convert any LayoutParams so that it works in our
            // FrameLayout
            FrameLayout.LayoutParams lp = convertEmptyViewLayoutParams(newEmptyView
                    .getLayoutParams());
            if (null != lp) {
                refreshableViewWrapper.addView(newEmptyView, lp);
            } else {
                refreshableViewWrapper.addView(newEmptyView);
            }
        }

        if (mRefreshableView instanceof EmptyViewMethodAccessor) {
            ((EmptyViewMethodAccessor) mRefreshableView).setEmptyViewInternal(newEmptyView);
        } else {
            // mRefreshableView.setEmptyView(newEmptyView);
        }
        mEmptyView = newEmptyView;
    }

    /**
     * Pass-through method for {@link PullToRefreshBase#getRefreshableView()
     * getRefreshableView()}. setOnItemClickListener(listener)}. This is just
     * for convenience!
     * 
     * @param listener - OnItemClickListener to use
     */
    public void setOnItemClickListener(HFListRecyclerAdapter.OnItemClickListener listener) {
       ViewUtils.getAdapter(mRefreshableView).setOnItemClickListener(listener);
    }

    public final void setOnLastItemVisibleListener(OnLastItemVisibleListener listener) {
        mOnLastItemVisibleListener = listener;
    }

    public final void setScrollEmptyView(boolean doScroll) {
        mScrollEmptyView = doScroll;
    }

    /**
     * Sets whether an indicator graphic should be displayed when the View is in
     * a state where a Pull-to-Refresh can happen. An example of this state is
     * when the Adapter View is scrolled to the top and the mode is set to
     * {@link Mode#PULL_FROM_START}
     * 
     * @param showIndicator - true if the indicators should be shown.
     */
    public void setShowIndicator(boolean showIndicator) {
        mShowIndicator = showIndicator;

        if (getShowIndicatorInternal()) {
            // If we're set to Show Indicator, add/update them
            addIndicatorViews();
        } else {
            // If not, then remove then
            removeIndicatorViews();
        }
    }

    ;

    @Override
    protected void onPullToRefresh() {
        super.onPullToRefresh();

        if (getShowIndicatorInternal()) {
            switch (getCurrentMode()) {
                case PULL_FROM_END:
                    mIndicatorIvBottom.pullToRefresh();
                    break;
                case PULL_FROM_START:
                    mIndicatorIvTop.pullToRefresh();
                    break;
                default:
                    // NO-OP
                    break;
            }
        }
    }

    protected void onRefreshing(boolean doScroll) {
        super.onRefreshing(doScroll);

        if (getShowIndicatorInternal()) {
            updateIndicatorViewsVisibility();
        }
    }

    @Override
    protected void onReleaseToRefresh() {
        super.onReleaseToRefresh();

        if (getShowIndicatorInternal()) {
            switch (getCurrentMode()) {
                case PULL_FROM_END:
                    mIndicatorIvBottom.releaseToRefresh();
                    break;
                case PULL_FROM_START:
                    mIndicatorIvTop.releaseToRefresh();
                    break;
                default:
                    // NO-OP
                    break;
            }
        }
    }

    @Override
    protected void onReset() {
        super.onReset();

        if (getShowIndicatorInternal()) {
            updateIndicatorViewsVisibility();
        }
    }

    @Override
    protected void handleStyledAttributes(TypedArray a) {
        // Set Show Indicator to the XML value, or default value
        mShowIndicator = a.getBoolean(R.styleable.PullToRefresh_ptrShowIndicator,
                !isPullToRefreshOverScrollEnabled());
    }

    protected boolean isReadyForPullStart() {
        return isFirstItemVisible();
    }

    protected boolean isReadyForPullEnd() {
        return isLastItemVisible();
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (null != mEmptyView && !mScrollEmptyView) {
            mEmptyView.scrollTo(-l, -t);
        }
    }

    @Override
    protected void updateUIForMode() {
        super.updateUIForMode();

        // Check Indicator Views consistent with new Mode
        if (getShowIndicatorInternal()) {
            addIndicatorViews();
        } else {
            removeIndicatorViews();
        }
    }

    private void addIndicatorViews() {
        Mode mode = getMode();
        FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();

        if (mode.showHeaderLoadingLayout() && null == mIndicatorIvTop) {
            // If the mode can pull down, and we don't have one set already
            mIndicatorIvTop = new IndicatorLayout(getContext(), Mode.PULL_FROM_START);
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            params.rightMargin = getResources().getDimensionPixelSize(
                    R.dimen.indicator_right_padding);
            params.gravity = Gravity.TOP | Gravity.RIGHT;
            refreshableViewWrapper.addView(mIndicatorIvTop, params);

        } else if (!mode.showHeaderLoadingLayout() && null != mIndicatorIvTop) {
            // If we can't pull down, but have a View then remove it
            refreshableViewWrapper.removeView(mIndicatorIvTop);
            mIndicatorIvTop = null;
        }

        if (mode.showFooterLoadingLayout() && null == mIndicatorIvBottom) {
            // If the mode can pull down, and we don't have one set already
            mIndicatorIvBottom = new IndicatorLayout(getContext(), Mode.PULL_FROM_END);
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            params.rightMargin = getResources().getDimensionPixelSize(
                    R.dimen.indicator_right_padding);
            params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
            refreshableViewWrapper.addView(mIndicatorIvBottom, params);

        } else if (!mode.showFooterLoadingLayout() && null != mIndicatorIvBottom) {
            // If we can't pull down, but have a View then remove it
            refreshableViewWrapper.removeView(mIndicatorIvBottom);
            mIndicatorIvBottom = null;
        }
    }

    private boolean getShowIndicatorInternal() {
        return mShowIndicator && isPullToRefreshEnabled();
    }

    private boolean isFirstItemVisible() {
        final HFListRecyclerAdapter adapter = ViewUtils.getAdapter(mRefreshableView);

        if (null == adapter || adapter.getItemCount() == 0) {

            return true;

        } else {

            /**
             * This check should really just be:
             * mRefreshableView.getFirstVisiblePosition() == 0, but PtRListView
             * internally use a HeaderView which messes the positions up. For
             * now we'll just add one to account for it and rely on the inner
             * condition which checks getTop().
             */
            if (((LinearLayoutManager) mRefreshableView.getLayoutManager())
                    .findFirstVisibleItemPosition() <= 1) {
                final View firstVisibleChild = mRefreshableView.getChildAt(0);
                if (firstVisibleChild != null) {
                    return firstVisibleChild.getTop() >= mRefreshableView.getTop();
                }
            }
        }

        return false;
    }

    private boolean isLastItemVisible() {
        final HFListRecyclerAdapter adapter = ViewUtils.getAdapter(mRefreshableView);

        if (null == adapter || adapter.getItemCount() == 0) {

            return true;
        } else {
            final int lastItemPosition = mRefreshableView.getLayoutManager().getItemCount() - 1;
            final int lastVisiblePosition = ((LinearLayoutManager) mRefreshableView
                    .getLayoutManager()).findLastVisibleItemPosition();

            /**
             * This check should really just be: lastVisiblePosition ==
             * lastItemPosition, but PtRListView internally uses a FooterView
             * which messes the positions up. For me we'll just subtract one to
             * account for it and rely on the inner condition which checks
             * getBottom().
             */
            if (lastVisiblePosition >= lastItemPosition - 1) {
                final int childIndex = lastVisiblePosition
                        - ((LinearLayoutManager) mRefreshableView.getLayoutManager())
                                .findFirstVisibleItemPosition();
                final View lastVisibleChild = mRefreshableView.getChildAt(childIndex);
                if (lastVisibleChild != null) {
                    return lastVisibleChild.getBottom() <= mRefreshableView.getBottom();
                }
            }
        }

        return false;
    }

    private void removeIndicatorViews() {
        if (null != mIndicatorIvTop) {
            getRefreshableViewWrapper().removeView(mIndicatorIvTop);
            mIndicatorIvTop = null;
        }

        if (null != mIndicatorIvBottom) {
            getRefreshableViewWrapper().removeView(mIndicatorIvBottom);
            mIndicatorIvBottom = null;
        }
    }

    private void updateIndicatorViewsVisibility() {
        if (null != mIndicatorIvTop) {
            if (!isRefreshing() && isReadyForPullStart()) {
                if (!mIndicatorIvTop.isVisible()) {
                    mIndicatorIvTop.show();
                }
            } else {
                if (mIndicatorIvTop.isVisible()) {
                    mIndicatorIvTop.hide();
                }
            }
        }

        if (null != mIndicatorIvBottom) {
            if (!isRefreshing() && isReadyForPullEnd()) {
                if (!mIndicatorIvBottom.isVisible()) {
                    mIndicatorIvBottom.show();
                }
            } else {
                if (mIndicatorIvBottom.isVisible()) {
                    mIndicatorIvBottom.hide();
                }
            }
        }
    }

    public void onLoadMore() {
        if (mOnLoadMoreListener != null) {
            mOnLoadMoreListener.onLoadMore();
        }
    }

    /**
     * Notify the loading more operation has finished
     */
    public void onLoadMoreComplete() {
        mIsLoadingMore = false;
        hideLoadMoreFooter();
    }

    /**
     * Interface definition for a callback to be invoked when list reaches the
     * last item (the user load more items in the list)
     */
    public interface OnLoadMoreListener {
        /**
         * Called when the list reaches the last item (the last item is visible
         * to the user)
         */
        public void onLoadMore();
    }

    private void hideLoadMoreFooter() {

        mFooterView.setVisibility(View.GONE);
        if (!isAddFront)
            mFooterView.setPadding(0, -mFooterView.getHeight(), 0, 0);
    }

    private void showLoadMoreFooter() {
        mFooterView.setVisibility(View.VISIBLE);
        mFooterView.setPadding(0, DensityUtils.dp2px(mContext, 10), 0,
                DensityUtils.dp2px(mContext, 10));
    }
    /*
     * public void removeLoadMoreFooter(){ if (getFooterViewsCount()==1){
     * removeFooterView(mFooterView); } } public void addLoadMoreFooter() { if
     * (getFooterViewsCount()==0){ addFooterView(mFooterView); } }
     */
    
  
}
